package graph_viewer.gui;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;

import java.io.*;
import java.util.Iterator;

import graph_viewer.app_exception.*;
import graph_viewer.canvas.*;
import graph_viewer.drawer.*;
import graph_viewer.experiment.*;
import graph_viewer.factory.*;
import graph_viewer.layout.*;
import graph_viewer.layout.layout_adjuster.*;
import graph_viewer.structure.*;
import graph_viewer.util.*;

public class App_GUI extends App_Frame implements GUI {
	//============================================================================
	// visual attributes
	//============================================================================
	static int
		WIDTH	= GUI_Util.get_screen_width_value(),
		HEIGHT	= GUI_Util.get_screen_height_value();
		
	static public final Rectangle	
		d_screen	= new Rectangle( WIDTH, HEIGHT );
		
	private Button 
		b_load		= new Button( "Load" ),
		b_setting	= new Button( "Setting" ),
		b_reset		= new Button( "Reset" ),
		b_close		= new Button( "Close" ),
		b_debug		= new Button( "Debug" ),
		b_remove_overlapping	
					= new Button( "Remove Overlapping" ),
		b_layout		= new Button( "Layout" ),
		b_print_image	= new Button( "Generate Image" ),
		b_exp		= new Button( "Experiment" );
	
	
	private JPanel	
		p_canvas, p_menu;
	
	private Drawer_Canvas	the_canvas;
	private String			canvas_type;

	static final String 
		INCLUSION_TREE_CANVAS	= Factory_Values.INCLUSION_TREE_CANVAS,
		GRAPH_CANVAS			= Factory_Values.GRAPH_CANVAS;
		
	static final private String
		EXPERIMENT	= 
							//Experiment.EXPERIMENT_CVC;
							//Experiment.EXPERIMENT_STATIC;
							Experiment.EXPERIMENT_DYNAMIC;
	//============================================================================
	//  functional attributes
	//============================================================================	
	private StringBuffer	log	= new StringBuffer();
	
	private String		data_file_name;
	private String		graph_type;

		
	public static void main( String args[] )  throws IOException{
		App_GUI main_frame;
		
		main_frame = new App_GUI();
		
		main_frame.setTitle( "Clustered Graph Viewer" );
		main_frame.pack();
		main_frame.setSize( d_screen.getSize() );
		main_frame.setVisible(true);
	}
	
	//============================================================================
	// constructors 
	//============================================================================
	public App_GUI()  throws IOException{ 
		this( GRAPH_CANVAS );
	}
	
	public App_GUI( String canvas_type )  throws IOException{
		set_canvas_type( canvas_type );
		
		build_gui();
		hookupEvents();		

		addWindowListener( 
			new WindowAdapter(){
				public void windowClosing( WindowEvent e ){
					System.exit( 0 );
				}
			}		
		);
	}
	
	//============================================================================
	// setter & getter
	//============================================================================
	public String get_data_file(){
		return this.data_file_name;
	}

	public void set_data_file( String a_file ){
		this.data_file_name	= a_file;
	}

	public String get_graph_type(){
		return this.the_canvas.get_graph_type();
	}

	public void set_graph_type( String type ){
		this.the_canvas.set_graph_type( type );
	}

	public String get_canvas_type(){
		return this.get_canvas_type();
	}

	public void set_canvas_type( String canvas_type ){
		this.canvas_type	=  canvas_type ;
	}
	
	public Drawer_Canvas get_canvas(){
		return this.the_canvas;
	}

	public void set_canvas( Drawer_Canvas gc ){
		this.the_canvas = gc;		
	}
	
	//============================================================================
	// private methods 
	//============================================================================
	private void initilize_env(){		
		/*set_has_label( true );
		set_has_DOI( false );
		set_is_closed( true ); 	
		*/
	}

	private void build_gui( )  throws IOException{		
		build_menu();
		build_output();					
	}

	private void build_output() throws IOException{
		p_canvas	= new JPanel(new BorderLayout());
		p_canvas.setBackground( Color.white );

		add_component( this, "Center", p_canvas );	
	}

	private void build_menu(){
		p_menu	= new JPanel( new FlowLayout( FlowLayout.LEFT) );

		p_menu.add( b_load );
		p_menu.add( b_setting );		
		p_menu.add( b_reset );
		p_menu.add( b_layout );		
		p_menu.add( b_exp );
		p_menu.add( b_remove_overlapping );		
		//p_menu.add( b_debug );
		p_menu.add( b_print_image );			
		p_menu.add( b_close );
		
		b_setting.setEnabled( false );// not enabled until data load.
		b_debug.setEnabled( false );// not enabled until data load.
		b_reset.setEnabled( false );// not enabled until data load.
		b_layout.setEnabled( false );// not enabled until data load.
		b_exp.setEnabled( false );// not enabled until data load.
		
		add_component( this, "South", p_menu );
	}
	
	private void hookupEvents() {
		b_load.addActionListener(
			new ActionListener(){
				public void actionPerformed( ActionEvent e){
					try{
						load_action();
					}catch ( IOException ioe ){
						Out.println( "Error when loading file!" );
					}
					
				}
			}
		);

		b_setting.addActionListener(
			new ActionListener(){
				public void actionPerformed( ActionEvent e){
					setting_action();
				}
			}
		);

		b_close.addActionListener(
			new ActionListener(){
				public void actionPerformed( ActionEvent e){
					close_action();
				}
			}
		);

		b_debug.addActionListener(
			new ActionListener(){
				public void actionPerformed( ActionEvent e){
					debug_action();
				}
			}
		);

		b_exp.addActionListener(
			new ActionListener(){
				public void actionPerformed( ActionEvent e){
					experiment_action();
				}
			}
		);

		b_layout.addActionListener(
			new ActionListener(){
				public void actionPerformed( ActionEvent e){
					layout_action();
				}
			}
		);

		b_remove_overlapping.addActionListener(
			new ActionListener(){
				public void actionPerformed( ActionEvent e){
					remove_overlapping_action();
				}
			}
		);

		b_print_image.addActionListener(
			new ActionListener(){
				public void actionPerformed( ActionEvent e){
					print_image_action();
				}
			}
		);

		b_reset.addActionListener(
			new ActionListener(){
				public void actionPerformed( ActionEvent e){
					reset_action();
				}
			}
		);
	}

	private void load_action() throws IOException{
		String data_file_name	= open_file();
		
		if ( data_file_name == null ){
			Out.println( "No data file loaded!" );
			return ;// do nothing
		}
		
		b_debug.setEnabled( true );	
		b_layout.setEnabled( true );	
		b_exp.setEnabled( true );

		set_data_file( data_file_name );
		clean_canvas();
		the_canvas	= new Graph_Canvas( data_file_name, p_canvas );	

		initialize_view();	
		
		print_node_positions();
	}
	
	private void debug_action(){
		Debug.trace_bug();
	}

	private void	layout_action(){
		initialize_view();
		repaint();
		
		print_node_positions();
	}
	
	private void print_node_positions(){
		Graph the_graph = this.get_canvas().get_graph();
		
		Log.print("======Node positions {x, y, w, h}======\n");
		for ( Iterator _i = the_graph.find_nodes().iterator(); _i.hasNext(); ){
			Node a_node	= (Node)_i.next();
			
			Log.print( a_node.toString() + a_node.get_position().toString() + "\n");
		}
		Log.print("=======================================\n");
	}
	
	void initialize_view(){	
		initilize_env();			
		
		p_canvas.add( the_canvas, "Center" );
		b_setting.setEnabled( true );
		b_reset.setEnabled( true );		

		//Debug.println( "the_canvas.draw_initial_view();", 10 );
		the_canvas.draw_initial_view();
		
		p_canvas.validate();
	}
	
	private void setting_action(){
		Setting_Frame f_setting	= new Setting_Frame( this );

		f_setting.pack();
		f_setting.setSize( f_setting.SIZE );	
		f_setting.setVisible(true);
	}
	
	void reset_action(){
		Debug.println( "GUI reset!", 4 );
		the_canvas.reset();

		repaint();
	}
	
	private void experiment_action(){
		if ( EXPERIMENT == Experiment.EXPERIMENT_CVC ){
			the_canvas.do_visual_complexity_experiment();
		}else if ( EXPERIMENT == Experiment.EXPERIMENT_STATIC ){
			the_canvas.do_static_experiment();
		} else if ( EXPERIMENT == Experiment.EXPERIMENT_DYNAMIC ){
			the_canvas.do_dynamic_experiment();
		}			
		
		repaint();	
	}
	
	//for test remove_overlapping
	private void remove_overlapping_action(){
		Debug.println( "GUI remove_overlapping_action!", 14 );

		Layout_Adjuster	 adjuster	= the_canvas.get_layout_adjuster();	
		
		Graph the_graph	= the_canvas.get_graph();

		adjuster.do_remove_node_overlapping_by_step( the_canvas );
				
		repaint();		
	}

	private void print_image_action(){
		this.the_canvas.generate_image();
	}

	private void close_action(){
		System.exit( 0 );	
	}

	private String open_file(){
		FileDialog	fc		= new FileDialog( this ); 
		
		fc.setMode(FileDialog.LOAD);		
		fc.show();		
		fc.setLocation(500, 500 );
		String 
			dir	 = fc.getDirectory(),	 
			selected_file = fc.getFile();

		if ( selected_file == null ){
			return null;
		}else{
			//Debug.println( "dir:" + dir + ", selected_file is " + selected_file, 4 ) ;
			return dir + selected_file;
		}
	}

	private void clean_canvas(){
		if ( this.the_canvas != null ){
			p_canvas.remove( the_canvas );
		}
	}	
}

class Setting_Frame extends App_Frame {	
	public Setting_Frame(){
		addWindowListener( 
			new WindowAdapter(){
				public void windowClosing( WindowEvent e ){
					dispose();
				}
			}		
		);
	}

	static final Dimension	SIZE	= new Dimension( 450, 220 );

	private App_GUI	f_parent;

	ButtonGroup
		layout_ButtonGroup, adjuster_ButtonGroup;

	private Button		
		b_ok		= new Button( "OK" ),
		b_cancel	= new Button( "Cancel" );

	//private boolean is_closed, is_distortion_at_center, has_label, has_DOI;
	
	private String layout_name, adjuster_name;

	public Setting_Frame( App_GUI parent_frame ){
		setTitle( "Setting" );
		f_parent	= parent_frame;
		initialize_env();

		build_gui();
		hookupEvents();
	}
	
	private void initialize_env(){
		Layout	layout	= f_parent.get_canvas().get_layout();
		Layout_Adjuster
				adjuster	= f_parent.get_canvas().get_layout_adjuster();


		layout_name		= layout.get_name();
		adjuster_name	= adjuster.get_name();
		
		Debug.println("current layout_name is: " + layout_name, 28 );
		Debug.println("current adjuster_name is: " + adjuster_name, 28 );
	}


	private void build_gui(){
		////Debug.println( "build_gui in setting frame started." );
		JPanel p_setting	= new JPanel( new BorderLayout() );
		JPanel 
			p_option		= build_option_panel(),				
			p_button		= new JPanel( new FlowLayout()  );
		
		JPanel[] option_panels = new JPanel[]
						{
							new JPanel(), // spring option
							new JPanel() //adjuster option
						};
	
		JRadioButton[]
			layout_JRadioButtons	= build_JRadioButtons( Layout.SPRING_VARIANTS),
			adjust_JRadioButtons	= build_JRadioButtons( Cluttered_Nodes_Adjuster.ADJUSTER_VARIANTS );
		
		layout_ButtonGroup	= build_ButtonGroup( layout_JRadioButtons,  layout_name  );
		adjuster_ButtonGroup	= build_ButtonGroup( adjust_JRadioButtons, adjuster_name );

		add_JRadioButtons( option_panels[0],  layout_JRadioButtons );//layout option
		add_JRadioButtons( option_panels[1], adjust_JRadioButtons );//adjuster option
		
		p_option.add( new Label("Layout") );
		p_option.add( option_panels[0] );
		p_option.add( new Label("Adjuster") );
		p_option.add( option_panels[1] );
		
		p_button.add( b_ok );
		p_button.add( b_cancel );
		
		p_setting.add( "Center", p_option );
		p_setting.add( "South", p_button );

		add_component( this, p_setting ) ;
	}
	
	private JPanel	build_option_panel(){
		JPanel p_option	= new JPanel();

		p_option.setLayout(new BoxLayout(p_option, BoxLayout.Y_AXIS));
		

		return p_option;
	}
	
	private void hookupEvents(){
		b_ok.addActionListener(
			new ActionListener(){
				public void actionPerformed( ActionEvent e  ){
					ok_action();	
				}			
			}
		);	
	
		b_cancel.addActionListener(
			new ActionListener(){
				public void actionPerformed( ActionEvent e  ){
					cancel_action();	
				}
			}
		);
	}

	private void ok_action(){
		JRadioButton	
			selected_layout_button = (JRadioButton)get_button_group_selected_item( layout_ButtonGroup ),
			selected_adjuster_button = (JRadioButton)get_button_group_selected_item( adjuster_ButtonGroup );

		String
			selected_layout_name	= selected_layout_button.getActionCommand(),
			selected_adjuster_name=selected_adjuster_button.getActionCommand();
		
		Debug.println( "selected_layout_name: " + selected_layout_name, 10 );
		Debug.println( "selected_adjuster_name: " + selected_adjuster_name, 10 );
	
		Drawer_Canvas the_canvas	= f_parent.get_canvas();		
		
		Layout	layout	= new Layout_Factory().create_layout( selected_layout_name );
		Layout_Adjuster
				adjuster	= new Layout_Factory().create_adjuster( selected_adjuster_name );
		
		the_canvas.set_layout( layout );
		the_canvas.set_layout_adjuster( adjuster );

		Debug.println( "layout set: " + the_canvas.get_layout().get_name(), 21 );
		Debug.println( "layout_adjsuter set: " + the_canvas.get_layout_adjuster().get_name(), 21 );

	
		this.setVisible(false);
	}

	private void cancel_action(){
		this.dispose();
	}
}
